home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / lkbackup.zip / lzip.c < prev    next >
C/C++ Source or Header  |  1993-10-25  |  37KB  |  1,231 lines

  1. /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
  2.  * Copyright (C) 1992-1993 Jean-loup Gailly
  3.  * The unzip code was written and put in the public domain by Mark Adler.
  4.  * Portions of the lzw code are derived from the public domain 'compress'
  5.  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
  6.  * Ken Turkowski, Dave Mack and Peter Jannesen.
  7.  *
  8.  * See the license_msg below and the file COPYING for the software license.
  9.  * See the file algorithm.doc for the compression algorithms and file formats.
  10.  */
  11.  
  12.   /* Modified 10/93 by l.g. kahn to provide compression/decompression
  13.      from a called function passing the input and output file names
  14.      also modified in many other places to support the compression for my tape backup
  15.      program.  */
  16.  
  17. static char  *license_msg[] = {
  18. "   Copyright (C) 1992-1993 Jean-loup Gailly",
  19. "   This program is free software; you can redistribute it and/or modify",
  20. "   it under the terms of the GNU General Public License as published by",
  21. "   the Free Software Foundation; either version 2, or (at your option)",
  22. "   any later version.",
  23. "",
  24. "   This program is distributed in the hope that it will be useful,",
  25. "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
  26. "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
  27. "   GNU General Public License for more details.",
  28. "",
  29. "   You should have received a copy of the GNU General Public License",
  30. "   along with this program; if not, write to the Free Software",
  31. "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
  32. 0};
  33.  
  34.  
  35.  /* Using gz on MSDOS would create too many file name conflicts. For
  36.  * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
  37.  * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
  38.  * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
  39.  * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. 
  40.  *
  41.  * For the meaning of all compilation flags, see comments in Makefile.in.
  42.  */
  43.  
  44. #ifdef RCSID
  45. static char rcsid[] = "$Id: gzip.c,v 1.25 1993/10/28 04:29:59 LKahn ESullivan Exp ESullivan $";
  46. #endif
  47.  
  48. #include <ctype.h>
  49. #include <sys/types.h>
  50. #include <signal.h>
  51. #include <sys/stat.h>
  52. #include <errno.h>
  53.  
  54. #include "tailor.h"
  55. #include "gzip.h"
  56. #include "lzw.h"
  57. #include "revision.h"
  58. #include "getopt.h"
  59.  
  60.         /* configuration */
  61.  
  62. #ifdef NO_TIME_H
  63. #  include <sys/time.h>
  64. #else
  65. #  include <time.h>
  66. #endif
  67.  
  68. #ifndef NO_FCNTL_H
  69. #  include <fcntl.h>
  70. #endif
  71.  
  72. #ifdef HAVE_UNISTD_H
  73. #  include <unistd.h>
  74. #endif
  75.  
  76. #if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
  77. #  include <stdlib.h>
  78. #else
  79.    extern int errno;
  80. #endif
  81.  
  82. #  include "ntdirent.h"
  83.    typedef struct dirent dir_type;
  84. #  define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
  85. #  define DIR_OPT "DIRENT"
  86.  
  87.  
  88. #ifndef NO_UTIME
  89. #  ifndef NO_UTIME_H
  90. #    include <utime.h>
  91. #    define TIME_OPT "UTIME"
  92. #  else
  93. #    ifdef HAVE_SYS_UTIME_H
  94. #      include <sys/utime.h>
  95. #      define TIME_OPT "SYS_UTIME"
  96. #    else
  97.        struct utimbuf {
  98.          time_t actime;
  99.          time_t modtime;
  100.        };
  101. #      define TIME_OPT ""
  102. #    endif
  103. #  endif
  104. #else
  105. #  define TIME_OPT "NO_UTIME"
  106. #endif
  107.  
  108. #if !defined(S_ISDIR) && defined(S_IFDIR)
  109. #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  110. #endif
  111. #if !defined(S_ISREG) && defined(S_IFREG)
  112. #  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  113. #endif
  114.  
  115. typedef RETSIGTYPE (*sig_type) OF((int));
  116.  
  117. #ifndef    O_BINARY
  118. #  define  O_BINARY  0  /* creation mode for open() */
  119. #endif
  120.  
  121. #ifndef O_CREAT
  122.    /* Pure BSD system? */
  123. // #  include <sys/file.h>
  124. #  ifndef O_CREAT
  125. #    define O_CREAT FCREAT
  126. #  endif
  127. #  ifndef O_EXCL
  128. #    define O_EXCL FEXCL
  129. #  endif
  130. #endif
  131.  
  132. #ifndef S_IRUSR
  133. #  define S_IRUSR 0400
  134. #endif
  135. #ifndef S_IWUSR
  136. #  define S_IWUSR 0200
  137. #endif
  138. #define RW_USER (S_IRUSR | S_IWUSR)  /* creation mode for open() */
  139.  
  140. #ifndef MAX_PATH_LEN
  141. #  define MAX_PATH_LEN   1024 /* max pathname length */
  142. #endif
  143.  
  144. #ifndef SEEK_END
  145. #  define SEEK_END 2
  146. #endif
  147.  
  148. #ifdef NO_OFF_T
  149.   typedef long off_t;
  150.   off_t lseek OF((int fd, off_t offset, int whence));
  151. #endif
  152.  
  153. /* Separator for file name parts (see shorten_name()) */
  154. #ifdef NO_MULTIPLE_DOTS
  155. #  define PART_SEP "-"
  156. #else
  157. #  define PART_SEP "."
  158. #endif
  159.  
  160.         /* global buffers */
  161.  
  162. DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  163. DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  164. DECLARE(ush, d_buf,  DIST_BUFSIZE);
  165. DECLARE(uch, window, 2L*WSIZE);
  166. #ifndef MAXSEG_64K
  167.     DECLARE(ush, tab_prefix, 1L<<BITS);
  168. #else
  169.     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
  170.     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
  171. #endif
  172.  
  173.         /* local variables */
  174.  
  175. int ascii = 0;        /* convert end-of-lines to local OS conventions */
  176. int to_stdout = 0;    /* output to stdout (-c) */
  177. int decompress = 0;   /* decompress (-d) */
  178. int force = 0;        /* don't ask questions, compress links (-f) */
  179. int no_name = -1;     /* don't save or restore the original file name */
  180. int no_time = -1;     /* don't save or restore the original file time */
  181. int recursive = 0;    /* recurse through directories (-r) */
  182. int list = 0;         /* list the file contents (-l) */
  183. int verbose = 0;      /* be verbose (-v) */
  184. int quiet = 0;        /* be very quiet (-q) */
  185. int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
  186. int test = 0;         /* test .gz file integrity */
  187. int foreground;       /* set if program run in foreground */
  188. char *progname;       /* program name */
  189. int maxbits = BITS;   /* max bits per code for LZW */
  190. int method = DEFLATED;/* compression method */
  191. int level = 6;        /* compression level */
  192. int exit_code = OK;   /* program exit code */
  193. int save_orig_name;   /* set if original name must be saved */
  194. int last_member;      /* set for .zip and .Z files */
  195. int part_nb;          /* number of parts in .gz file */
  196. long time_stamp;      /* original time stamp (modification time) */
  197. long ifile_size;      /* input file size, -1 for devices (debug only) */
  198. char *env;            /* contents of GZIP env variable */
  199. char **args = NULL;   /* argv pointer if GZIP env variable defined */
  200. char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
  201. int  z_len;           /* strlen(z_suffix) */
  202.  
  203. long bytes_in;             /* number of input bytes */
  204. long bytes_out;            /* number of output bytes */
  205. long total_in = 0;         /* input bytes for all files */
  206. long total_out = 0;        /* output bytes for all files */
  207. char ifname[MAX_PATH_LEN]; /* input file name */
  208. char ofname[MAX_PATH_LEN]; /* output file name */
  209. int  remove_ofname = 0;       /* remove output file on error */
  210. struct stat istat;         /* status for input file */
  211. int  ifd;                  /* input file descriptor */
  212. int  ofd;                  /* output file descriptor */
  213. unsigned insize;           /* valid bytes in inbuf */
  214. unsigned inptr;            /* index of next byte to be processed in inbuf */
  215. unsigned outcnt;           /* bytes in output buffer */
  216.  
  217. struct option longopts[] =
  218. {
  219.  /* { name  has_arg  *flag  val } */
  220.     {"ascii",      0, 0, 'a'}, /* ascii text mode */
  221.     {"to-stdout",  0, 0, 'c'}, /* write output on standard output */
  222.     {"stdout",     0, 0, 'c'}, /* write output on standard output */
  223.     {"decompress", 0, 0, 'd'}, /* decompress */
  224.     {"uncompress", 0, 0, 'd'}, /* decompress */
  225.  /* {"encrypt",    0, 0, 'e'},    encrypt */
  226.     {"force",      0, 0, 'f'}, /* force overwrite of output file */
  227.     {"help",       0, 0, 'h'}, /* give help */
  228.  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
  229.     {"list",       0, 0, 'l'}, /* list .gz file contents */
  230.     {"license",    0, 0, 'L'}, /* display software license */
  231.     {"no-name",    0, 0, 'n'}, /* don't save or restore original name & time */
  232.     {"name",       0, 0, 'N'}, /* save or restore original name & time */
  233.     {"quiet",      0, 0, 'q'}, /* quiet mode */
  234.     {"silent",     0, 0, 'q'}, /* quiet mode */
  235.     {"recursive",  0, 0, 'r'}, /* recurse through directories */
  236.     {"suffix",     1, 0, 'S'}, /* use given suffix instead of .gz */
  237.     {"test",       0, 0, 't'}, /* test compressed file integrity */
  238.     {"no-time",    0, 0, 'T'}, /* don't save or restore the time stamp */
  239.     {"verbose",    0, 0, 'v'}, /* verbose mode */
  240.     {"version",    0, 0, 'V'}, /* display version number */
  241.     {"fast",       0, 0, '1'}, /* compress faster */
  242.     {"best",       0, 0, '9'}, /* compress better */
  243.     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
  244.     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
  245.     { 0, 0, 0, 0 }
  246. };
  247.  
  248. /* local functions */
  249.  
  250. local int treat_file   OF((char *iname));
  251. local int create_outfile OF((void));
  252. local int  do_stat      OF((char *name, struct stat *sbuf));
  253. local int  get_istat    OF((char *iname, struct stat *sbuf));
  254. local int  same_file    OF((struct stat *stat1, struct stat *stat2));
  255. local int  get_method   OF((int in));
  256. local int name_too_long OF((char *name, struct stat *statb));
  257. local void do_list      OF((int ifd, int method));
  258. local int  check_ofname OF((void));
  259. local void copy_stat    OF((struct stat *ifstat));
  260. local int do_exit      OF((int exitcode));
  261. int (*work) OF((int infile, int outfile)) = zip; /* function to call */
  262.  
  263. #ifndef NO_DIR
  264. local void treat_dir    OF((char *dir));
  265. #endif
  266. #ifndef NO_UTIME
  267. local void reset_times  OF((char *name, struct stat *statb));
  268. #endif
  269.  
  270. #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
  271.  
  272.  
  273.  
  274. /* lgk new linkage call routine so that we don't have the overhead of
  275. calling system to perform compression, we also changed it so that
  276. a new output file is not created from the input, and the output file is not deleted
  277. after compressoin */
  278.  
  279. /* format is gzip_compress(input_filename, output_filename) */
  280.  
  281. int gzip_compress(input_file,output_file)
  282.  char *input_file;
  283.  char *output_file;
  284.   {
  285.     
  286.     int rvalue = 0;
  287.     /* set flag not to store name and time in compressed file */
  288.     no_name = no_time = 1;
  289.      force = 1;
  290.  
  291.      exit_code = 0;
  292.     /* Allocate all global buffers (for DYN_ALLOC option) */
  293.     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  294.     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  295.     ALLOC(ush, d_buf,  DIST_BUFSIZE);
  296.     ALLOC(uch, window, 2L*WSIZE);
  297. #ifndef MAXSEG_64K
  298.     ALLOC(ush, tab_prefix, 1L<<BITS);
  299. #else
  300.     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
  301.     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
  302. #endif
  303.  
  304.     strcpy(ifname,input_file);
  305.     strcpy(ofname,output_file);
  306.     to_stdout = 0;
  307.     test = 0;
  308.     list = 0;
  309.     decompress = 0;
  310.     ascii = 0;
  311.      /* And get to work */
  312.   rvalue = treat_file(ifname);
  313.    
  314.     if (rvalue != 0)
  315.       return(do_exit(1));
  316.     do_exit(exit_code);
  317.     return(0);
  318.   }
  319.  
  320. int gzip_decompress(input_file,output_file)
  321.  char *input_file;
  322.  char *output_file;
  323.   {
  324.      int rvalue = 0;
  325.     /* set flag not to store name and time in compressed file */
  326.     no_name = no_time = 1;
  327.           force = 1;
  328.  
  329.     exit_code = 0;
  330.     /* Allocate all global buffers (for DYN_ALLOC option) */
  331.     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  332.     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  333.     ALLOC(ush, d_buf,  DIST_BUFSIZE);
  334.     ALLOC(uch, window, 2L*WSIZE);
  335. #ifndef MAXSEG_64K
  336.     ALLOC(ush, tab_prefix, 1L<<BITS);
  337. #else
  338.     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
  339.     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
  340. #endif
  341.  
  342.     strcpy(ifname,input_file);
  343.     strcpy(ofname,output_file);
  344.     to_stdout = 0;
  345.     test = 0;
  346.     list = 0;
  347.     decompress = 1;
  348.     ascii = 0;
  349.  
  350.     /* And get to work */
  351.     rvalue = treat_file(ifname);
  352.     if (rvalue != 0)
  353.       return(do_exit(1));
  354.     do_exit(exit_code);
  355.     return(0);
  356.   }
  357.  
  358.    /* lgk main test program */
  359.  /*
  360.    int main(argc,argv)
  361.    int argc;
  362.    char *argv[];
  363.  
  364.    {
  365.  
  366.     int rvalue = 0;
  367.  
  368.     
  369.     if (argc < 4)
  370.       {
  371.        printf("Error needs three parameters ie c inname outname \n");
  372.        fflush(stdout);
  373.        return(1);
  374.        }
  375.     printf("argv 1 = %s argv 2 = %s argv 3 = %s \n",argv[1],argv[2],argv[3]);
  376.     fflush(stdout);
  377.  
  378.     switch (argv[1][0])
  379.      {
  380.       case 'c':
  381.        printf("compressing %s to %s \n",argv[2],argv[3]);
  382.        fflush(stdout);
  383.        rvalue = gzip_compress(argv[2],argv[3]);
  384.        printf("return value = %d \n",rvalue);
  385.        fflush(stdout);
  386.        break;
  387.  
  388.       case 'd':
  389.        printf("decompressing %s to %s \n",argv[2],argv[3]);
  390.        fflush(stdout);
  391.        rvalue = gzip_decompress(argv[2],argv[3]);
  392.        printf("return value = %d \n",rvalue);
  393.        fflush(stdout);
  394.        break;
  395.  
  396.       default:
  397.         printf("error in test first parameter is not d or c \n");
  398.         fflush(stdout);
  399.         break;
  400.  
  401.      }
  402.  
  403.     return(0);
  404.  }
  405.  
  406.         
  407.  
  408.  
  409. /* ========================================================================
  410.  * Compress or decompress the given file
  411.  */
  412. local int treat_file(iname)
  413.     char *iname;
  414. {
  415.    
  416.     /* Check if the input file is present, set ifname and istat: */
  417.     if (get_istat(iname, &istat) != OK) 
  418.       return(1);
  419.  
  420.     /* If the input name is that of a directory, recurse or ignore: */
  421.     if (S_ISDIR(istat.st_mode)) 
  422.      {
  423.       WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
  424.       return (1);
  425.      }
  426.  
  427.     if (!S_ISREG(istat.st_mode))
  428.       {
  429.           WARN((stderr,
  430.           "%s: %s is not a directory or a regular file - ignored\n",
  431.           progname, ifname));
  432.          return (1);
  433.       }
  434.   
  435.     ifile_size = istat.st_size;
  436.     time_stamp = no_time && !list ? 0 : istat.st_mtime;
  437.  
  438.     /* Generate output file name. For -r and (-t or -l), skip files
  439.      * without a valid gzip suffix (check done in make_ofname).
  440.      */
  441.   
  442.     /* Open the input file and determine compression method. The mode
  443.      * parameter is ignored but required by some systems (VMS) and forbidden
  444.      * on other systems (MacOS).
  445.      */
  446.     ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY,
  447.            RW_USER);
  448.     if (ifd == -1) 
  449.       {
  450.         fprintf(stderr, "%s: ", progname);
  451.         perror(ifname);
  452.         exit_code = ERROR;
  453.         return (1);
  454.       }
  455.     clear_bufs(); /* clear input and output buffers */
  456.     part_nb = 0;
  457.  
  458.     if (decompress)
  459.       {
  460.        method = get_method(ifd); /* updates ofname if original given */
  461.        if (method < 0) 
  462.          {
  463.           close(ifd);
  464.           return(1);               /* error message already emitted */
  465.          }
  466.        }
  467.   
  468.     /* lgk don't check the name here simply overwrite it since we decompress to
  469.     a temp file name anyway this check just takes extra time.
  470.     */
  471.  
  472.     /* If compressing to a file, check if ofname is not ambiguous
  473.      * because the operating system truncates names. Otherwise, generate
  474.      * a new ofname and save the original name in the compressed file.
  475.      */
  476.      if (create_outfile() != OK)
  477.        return(1);
  478.  
  479.   
  480.     /* Keep the name even if not truncated except with --no-name: */
  481.     if (!save_orig_name) save_orig_name = !no_name;
  482.  
  483.    
  484.     /* Actually do the compression/decompression. Loop over zipped members.
  485.      */
  486.     for (;;) 
  487.        {
  488.         if ((*work)(ifd, ofd) != OK) 
  489.           {
  490.            method = -1; /* force cleanup */
  491.            break;
  492.           }
  493.  
  494.         if (!decompress || last_member || inptr == insize) 
  495.           break;
  496.         /* end of file */
  497.  
  498.         method = get_method(ifd);
  499.         if (method < 0)
  500.           break;    /* error message already emitted */
  501.         bytes_out = 0;            /* required for length check */
  502.        } /* end of loop */
  503.  
  504.     close(ifd);
  505.     if (!to_stdout && close(ofd)) 
  506.       {
  507.        write_error();
  508.       }
  509.     if (method == -1) 
  510.       {
  511.        if (!to_stdout) 
  512.          unlink (ofname); /* deletes partial file if it fails lgk */
  513.        return(1);
  514.       }
  515.    
  516.     /* Copy modes, times, ownership, and remove the input file */
  517.     /* lgk modified copy_stat so input file is not deleted */
  518.  
  519.     if (!to_stdout) 
  520.       {
  521.        copy_stat(&istat);
  522.       }
  523.  
  524. return(0);
  525. }
  526.  
  527. /* ========================================================================
  528.  * Create the output file. Return OK or ERROR.
  529.  * Try several times if necessary to avoid truncating the z_suffix. For
  530.  * example, do not create a compressed file of name "1234567890123."
  531.  * Sets save_orig_name to true if the file name has been truncated.
  532.  * IN assertions: the input file has already been open (ifd is set) and
  533.  *   ofname has already been updated if there was an original name.
  534.  * OUT assertions: ifd and ofd are closed in case of error.
  535.  */
  536. local int create_outfile()
  537. {
  538.     struct stat    ostat; /* stat for ofname */
  539.     int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
  540.  
  541.     if (ascii && decompress) {
  542.     flags &= ~O_BINARY; /* force ascii text mode */
  543.     }
  544.     for (;;) {
  545.     /* Make sure that ofname is not an existing file */
  546.     if (check_ofname() != OK) {
  547.         close(ifd);
  548.         return ERROR;
  549.     }
  550.     /* Create the output file */
  551.     remove_ofname = 1;
  552.     ofd = OPEN(ofname, flags, RW_USER);
  553.     if (ofd == -1) {
  554.         perror(ofname);
  555.         close(ifd);
  556.         exit_code = ERROR;
  557.         return ERROR;
  558.     }
  559.  
  560.     /* Check for name truncation on new file (1234567890123.gz) */
  561. #ifdef NO_FSTAT
  562.     if (stat(ofname, &ostat) != 0) {
  563. #else
  564.     if (fstat(ofd, &ostat) != 0) {
  565. #endif
  566.         fprintf(stderr, "%s: ", progname);
  567.         perror(ofname);
  568.         close(ifd); close(ofd);
  569.         unlink(ofname);
  570.         exit_code = ERROR;
  571.         return ERROR;
  572.     }
  573.     if (!name_too_long(ofname, &ostat)) return OK;
  574.  
  575.     if (decompress) {
  576.         /* name might be too long if an original name was saved */
  577.         WARN((stderr, "%s: %s: warning, name truncated\n",
  578.           progname, ofname));
  579.         return OK;
  580.     }
  581.     close(ofd);
  582.     unlink(ofname);
  583. #ifdef NO_MULTIPLE_DOTS
  584.     /* Should never happen, see check_ofname() */
  585.     fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
  586.     do_exit(ERROR);
  587. #endif
  588.     //shorten_name(ofname);
  589.     }
  590. }
  591.  
  592. /* ========================================================================
  593.  * Use lstat if available, except for -c or -f. Use stat otherwise.
  594.  * This allows links when not removing the original file.
  595.  */
  596. local int do_stat(name, sbuf)
  597.     char *name;
  598.     struct stat *sbuf;
  599. {
  600.     errno = 0;
  601. #if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
  602.     if (!to_stdout && !force) {
  603.     return lstat(name, sbuf);
  604.     }
  605. #endif
  606.     return stat(name, sbuf);
  607. }
  608.  
  609.  
  610. /* ========================================================================
  611.  * Set ifname to the input file name (with a suffix appended if necessary)
  612.  * and istat to its stats. For decompression, if no file exists with the
  613.  * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
  614.  * For MSDOS, we try only z_suffix and z.
  615.  * Return OK or ERROR.
  616.  */
  617. local int get_istat(iname, sbuf)
  618.     char *iname;
  619.     struct stat *sbuf;
  620. {
  621.     int ilen;  /* strlen(ifname) */
  622.     static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
  623.     char **suf = suffixes;
  624.     char *s;
  625. #ifdef NO_MULTIPLE_DOTS
  626.     char *dot; /* pointer to ifname extension, or NULL */
  627. #endif
  628.  
  629.     strcpy(ifname, iname);
  630.  
  631.     /* If input file exists, return OK. */
  632.     if (do_stat(ifname, sbuf) == 0) return OK;
  633.  
  634.     if (!decompress || errno != ENOENT) {
  635.     perror(ifname);
  636.     exit_code = ERROR;
  637.     return ERROR;
  638.     }
  639.     /* file.ext doesn't exist, try adding a suffix (after removing any
  640.      * version number for VMS).
  641.      */                         /* lgk we don't need suffix code
  642.     //s = get_suffix(ifname);
  643.     if (s != NULL) {
  644.     perror(ifname); /* ifname already has z suffix and does not exist */
  645.     //exit_code = ERROR;
  646.     //return ERROR;
  647.     //}
  648.  
  649. #ifdef NO_MULTIPLE_DOTS
  650.     dot = strrchr(ifname, '.');
  651.     if (dot == NULL) {
  652.         strcat(ifname, ".");
  653.         dot = strrchr(ifname, '.');
  654.     }
  655. #endif
  656.     ilen = strlen(ifname);
  657.     if (strequ(z_suffix, ".gz")) suf++;
  658.  
  659.     /* Search for all suffixes */
  660.     do {
  661.         s = *suf;
  662. #ifdef NO_MULTIPLE_DOTS
  663.         if (*s == '.') s++;
  664. #endif
  665. #ifdef MAX_EXT_CHARS
  666.         strcpy(ifname, iname);
  667.         /* Needed if the suffixes are not sorted by increasing length */
  668.  
  669.         if (*dot == '\0') strcpy(dot, ".");
  670.         dot[MAX_EXT_CHARS+1-strlen(s)] = '\0';
  671. #endif
  672.         strcat(ifname, s);
  673.         if (do_stat(ifname, sbuf) == 0) return OK;
  674.     ifname[ilen] = '\0';
  675.     } while (*++suf != NULL);
  676.  
  677.     /* No suffix found, complain using z_suffix: */
  678. #ifdef MAX_EXT_CHARS
  679.     strcpy(ifname, iname);
  680.     if (*dot == '\0') strcpy(dot, ".");
  681.     dot[MAX_EXT_CHARS+1-z_len] = '\0';
  682. #endif
  683.     strcat(ifname, z_suffix);
  684.     perror(ifname);
  685.     exit_code = ERROR;
  686.     return ERROR;
  687. }
  688.  
  689.  
  690.  
  691. /* ========================================================================
  692.  * Check the magic number of the input file and update ofname if an
  693.  * original name was given and to_stdout is not set.
  694.  * Return the compression method, -1 for error, -2 for warning.
  695.  * Set inptr to the offset of the next byte to be processed.
  696.  * Updates time_stamp if there is one and --no-time is not used.
  697.  * This function may be called repeatedly for an input file consisting
  698.  * of several contiguous gzip'ed members.
  699.  * IN assertions: there is at least one remaining compressed member.
  700.  *   If the member is a zip file, it must be the only one.
  701.  */
  702. local int get_method(in)
  703.     int in;        /* input file descriptor */
  704. {
  705.     uch flags;     /* compression flags */
  706.     char magic[2]; /* magic header */
  707.     ulg stamp;     /* time stamp */
  708.  
  709.     /* If --force and --stdout, zcat == cat, so do not complain about
  710.      * premature end of file: use try_byte instead of get_byte.
  711.      */
  712.     if (force && to_stdout) {
  713.     magic[0] = (char)try_byte();
  714.     magic[1] = (char)try_byte();
  715.     /* If try_byte returned EOF, magic[1] == 0xff */
  716.     } else {
  717.     magic[0] = (char)get_byte();
  718.     magic[1] = (char)get_byte();
  719.     }
  720.     method = -1;                 /* unknown yet */
  721.     part_nb++;                   /* number of parts in gzip file */
  722.     header_bytes = 0;
  723.     last_member = RECORD_IO;
  724.     /* assume multiple members in gzip file except for record oriented I/O */
  725.  
  726.     if (memcmp(magic, GZIP_MAGIC, 2) == 0
  727.         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
  728.  
  729.     method = (int)get_byte();
  730.     if (method != DEFLATED) {
  731.         fprintf(stderr,
  732.             "%s: %s: unknown method %d -- get newer version of gzip\n",
  733.             progname, ifname, method);
  734.         exit_code = ERROR;
  735.         return -1;
  736.     }
  737.     work = unzip;
  738.     flags  = (uch)get_byte();
  739.  
  740.     if ((flags & ENCRYPTED) != 0) {
  741.         fprintf(stderr,
  742.             "%s: %s is encrypted -- get newer version of gzip\n",
  743.             progname, ifname);
  744.         exit_code = ERROR;
  745.         return -1;
  746.     }
  747.     if ((flags & CONTINUATION) != 0) {
  748.         fprintf(stderr,
  749.        "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
  750.             progname, ifname);
  751.         exit_code = ERROR;
  752.         if (force <= 1) return -1;
  753.     }
  754.     if ((flags & RESERVED) != 0) {
  755.         fprintf(stderr,
  756.             "%s: %s has flags 0x%x -- get newer version of gzip\n",
  757.             progname, ifname, flags);
  758.         exit_code = ERROR;
  759.         if (force <= 1) return -1;
  760.     }
  761.     stamp  = (ulg)get_byte();
  762.     stamp |= ((ulg)get_byte()) << 8;
  763.     stamp |= ((ulg)get_byte()) << 16;
  764.     stamp |= ((ulg)get_byte()) << 24;
  765.     if (stamp != 0 && !no_time) time_stamp = stamp;
  766.  
  767.     (void)get_byte();  /* Ignore extra flags for the moment */
  768.     (void)get_byte();  /* Ignore OS type for the moment */
  769.  
  770.     if ((flags & CONTINUATION) != 0) {
  771.         unsigned part = (unsigned)get_byte();
  772.         part |= ((unsigned)get_byte())<<8;
  773.         if (verbose) {
  774.         fprintf(stderr,"%s: %s: part number %u\n",
  775.             progname, ifname, part);
  776.         }
  777.     }
  778.     if ((flags & EXTRA_FIELD) != 0) {
  779.         unsigned len = (unsigned)get_byte();
  780.         len |= ((unsigned)get_byte())<<8;
  781.         if (verbose) {
  782.         fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
  783.             progname, ifname, len);
  784.         }
  785.         while (len--) (void)get_byte();
  786.     }
  787.  
  788.     /* Get original file name if it was truncated */
  789.     if ((flags & ORIG_NAME) != 0) {
  790.         if (no_name || (to_stdout && !list) || part_nb > 1) {
  791.         /* Discard the old name */
  792.         char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
  793.         do {c=get_byte();} while (c != 0);
  794.         } else {
  795.         /* Copy the base name. Keep a directory prefix intact. */
  796.                 char *p = basename(ofname);
  797.                 char *base = p;
  798.         for (;;) {
  799.             *p = (char)get_char();
  800.             if (*p++ == '\0') break;
  801.             if (p >= ofname+sizeof(ofname)) {
  802.             error("corrupted input -- file name too large");
  803.             }
  804.         }
  805.                 /* If necessary, adapt the name to local OS conventions: */
  806.                 if (!list) {
  807.                    MAKE_LEGAL_NAME(base);
  808.            if (base) list=0; /* avoid warning about unused variable */
  809.                 }
  810.         } /* no_name || to_stdout */
  811.     } /* ORIG_NAME */
  812.  
  813.     /* Discard file comment if any */
  814.     if ((flags & COMMENT) != 0) {
  815.         while (get_char() != 0) /* null */ ;
  816.     }
  817.     if (part_nb == 1) {
  818.         header_bytes = inptr + 2*sizeof(long); /* include crc and size */
  819.     }
  820.  
  821.     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
  822.         && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
  823.     /* To simplify the code, we support a zip file when alone only.
  824.          * We are thus guaranteed that the entire local header fits in inbuf.
  825.          */
  826.         inptr = 0;
  827.     work = unzip;
  828.     if (check_zipfile(in) != OK) return -1;
  829.     /* check_zipfile may get ofname from the local header */
  830.     last_member = 1;
  831.  
  832.     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
  833.     work = unpack;
  834.     method = PACKED;
  835.  
  836.     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
  837.     work = unlzw;
  838.     method = COMPRESSED;
  839.     last_member = 1;
  840.  
  841.     } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
  842.     work = unlzh;
  843.     method = LZHED;
  844.     last_member = 1;
  845.  
  846.     } else if (force && to_stdout && !list) { /* pass input unchanged */
  847.     method = STORED;
  848.     work = copy;
  849.         inptr = 0;
  850.     last_member = 1;
  851.     }
  852.     if (method >= 0) return method;
  853.  
  854.     if (part_nb == 1) {
  855.     fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
  856.     exit_code = ERROR;
  857.     return -1;
  858.     } else {
  859.     WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
  860.           progname, ifname));
  861.     return -2;
  862.     }
  863. }
  864.  
  865. /* ========================================================================
  866.  * Display the characteristics of the compressed file.
  867.  * If the given method is < 0, display the accumulated totals.
  868.  * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
  869.  */
  870. local void do_list(ifd, method)
  871.     int ifd;     /* input file descriptor */
  872.     int method;  /* compression method */
  873. {
  874.     ulg crc;  /* original crc */
  875.     static int first_time = 1;
  876.     static char* methods[MAX_METHODS] = {
  877.         "store",  /* 0 */
  878.         "compr",  /* 1 */
  879.         "pack ",  /* 2 */
  880.         "lzh  ",  /* 3 */
  881.         "", "", "", "", /* 4 to 7 reserved */
  882.         "defla"}; /* 8 */
  883.     char *date;
  884.  
  885.     if (first_time && method >= 0) {
  886.     first_time = 0;
  887.     if (verbose)  {
  888.         printf("method  crc     date  time  ");
  889.     }
  890.     if (!quiet) {
  891.         printf("compressed  uncompr. ratio uncompressed_name\n");
  892.     }
  893.     } else if (method < 0) {
  894.     if (total_in <= 0 || total_out <= 0) return;
  895.     if (verbose) {
  896.         printf("                            %9lu %9lu ",
  897.            total_in, total_out);
  898.     } else if (!quiet) {
  899.         printf("%9ld %9ld ", total_in, total_out);
  900.     }
  901.     display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
  902.     /* header_bytes is not meaningful but used to ensure the same
  903.      * ratio if there is a single file.
  904.      */
  905.     printf(" (totals)\n");
  906.     return;
  907.     }
  908.     crc = (ulg)~0; /* unknown */
  909.     bytes_out = -1L;
  910.     bytes_in = ifile_size;
  911.  
  912. #if RECORD_IO == 0
  913.     if (method == DEFLATED && !last_member) {
  914.         /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
  915.          * If the lseek fails, we could use read() to get to the end, but
  916.          * --list is used to get quick results.
  917.          * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
  918.          * you are not concerned about speed.
  919.          */
  920.         bytes_in = (long)lseek(ifd, (off_t)(-8), SEEK_END);
  921.         if (bytes_in != -1L) {
  922.             uch buf[8];
  923.             bytes_in += 8L;
  924.             if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
  925.                 read_error();
  926.             }
  927.             crc       = LG(buf);
  928.         bytes_out = LG(buf+4);
  929.     }
  930.     }
  931. #endif /* RECORD_IO */
  932.     date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
  933.     date[12] = '\0';               /* suppress the 1/100sec and the year */
  934.     if (verbose) {
  935.         printf("%5s %08lx %11s ", methods[method], crc, date);
  936.     }
  937.     printf("%9ld %9ld ", bytes_in, bytes_out);
  938.     if (bytes_in  == -1L) {
  939.     total_in = -1L;
  940.     bytes_in = bytes_out = header_bytes = 0;
  941.     } else if (total_in >= 0) {
  942.     total_in  += bytes_in;
  943.     }
  944.     if (bytes_out == -1L) {
  945.     total_out = -1L;
  946.     bytes_in = bytes_out = header_bytes = 0;
  947.     } else if (total_out >= 0) {
  948.     total_out += bytes_out;
  949.     }
  950.     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
  951.     printf(" %s\n", ofname);
  952. }
  953.  
  954. /* ========================================================================
  955.  * Return true if the two stat structures correspond to the same file.
  956.  */
  957. local int same_file(stat1, stat2)
  958.     struct stat *stat1;
  959.     struct stat *stat2;
  960. {
  961.     return stat1->st_ino   == stat2->st_ino
  962.     && stat1->st_dev   == stat2->st_dev
  963. #ifdef NO_ST_INO
  964.         /* Can't rely on st_ino and st_dev, use other fields: */
  965.     && stat1->st_mode  == stat2->st_mode
  966.     && stat1->st_uid   == stat2->st_uid
  967.     && stat1->st_gid   == stat2->st_gid
  968.     && stat1->st_size  == stat2->st_size
  969.     && stat1->st_atime == stat2->st_atime
  970.     && stat1->st_mtime == stat2->st_mtime
  971.     && stat1->st_ctime == stat2->st_ctime
  972. #endif
  973.         ;
  974. }
  975.  
  976. /* ========================================================================
  977.  * Return true if a file name is ambiguous because the operating system
  978.  * truncates file names.
  979.  */
  980. local int name_too_long(name, statb)
  981.     char *name;           /* file name to check */
  982.     struct stat *statb;   /* stat buf for this file name */
  983. {
  984.     int s = strlen(name);
  985.     char c = name[s-1];
  986.     struct stat    tstat; /* stat for truncated name */
  987.     int res;
  988.  
  989.     tstat = *statb;      /* Just in case OS does not fill all fields */
  990.     name[s-1] = '\0';
  991.     res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
  992.     name[s-1] = c;
  993.     Trace((stderr, " too_long(%s) => %d\n", name, res));
  994.     return res;
  995. }
  996.  
  997.  
  998. /* ========================================================================
  999.  * If compressing to a file, check if ofname is not ambiguous
  1000.  * because the operating system truncates names. Otherwise, generate
  1001.  * a new ofname and save the original name in the compressed file.
  1002.  * If the compressed file already exists, ask for confirmation.
  1003.  *    The check for name truncation is made dynamically, because different
  1004.  * file systems on the same OS might use different truncation rules (on SVR4
  1005.  * s5 truncates to 14 chars and ufs does not truncate).
  1006.  *    This function returns -1 if the file must be skipped, and
  1007.  * updates save_orig_name if necessary.
  1008.  * IN assertions: save_orig_name is already set if ofname has been
  1009.  * already truncated because of NO_MULTIPLE_DOTS. The input file has
  1010.  * already been open and istat is set.
  1011.  */
  1012. local int check_ofname()
  1013. {
  1014.     struct stat    ostat; /* stat for ofname */
  1015.  
  1016.  
  1017.     if (stat(ofname, &ostat) != 0) return 0;
  1018.  
  1019.   
  1020.     /* Check that the input and output files are different (could be
  1021.      * the same by name truncation or links).
  1022.      */
  1023.     if (same_file(&istat, &ostat)) 
  1024.       {
  1025.        if (strequ(ifname, ofname)) 
  1026.           {
  1027.            fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
  1028.              progname, ifname, decompress ? "de" : "");
  1029.           }
  1030.         else 
  1031.          {
  1032.            fprintf(stderr, "%s: %s and %s are the same file\n",
  1033.              progname, ifname, ofname);
  1034.           }
  1035.         exit_code = ERROR;
  1036.         return ERROR;
  1037.       }
  1038.  
  1039.     /* Ask permission to overwrite the existing file */
  1040.     if (!force) 
  1041.       {
  1042.        char response[80];
  1043.        strcpy(response,"n");
  1044.         fprintf(stderr, "%s already exists;", ofname);
  1045.        fprintf(stderr, " do you wish to overwrite (y or n)? ");
  1046.        fflush(stderr);
  1047.            (void)fgets(response, sizeof(response)-1, stdin);
  1048.       
  1049.        if (tolow(*response) != 'y') 
  1050.         {
  1051.           fprintf(stderr, "\tnot overwritten\n");
  1052.           if (exit_code == OK) exit_code = WARNING;
  1053.           return ERROR;
  1054.         }
  1055.       }
  1056.     
  1057.     if (unlink(ofname)) 
  1058.       {
  1059.        fprintf(stderr, "%s: ", progname);
  1060.        perror(ofname);
  1061.        exit_code = ERROR;
  1062.        return ERROR;
  1063.       }
  1064.     
  1065.     return OK;
  1066. }
  1067.  
  1068.  
  1069. #ifndef NO_UTIME
  1070. /* ========================================================================
  1071.  * Set the access and modification times from the given stat buffer.
  1072.  */
  1073. local void reset_times (name, statb)
  1074.     char *name;
  1075.     struct stat *statb;
  1076. {
  1077.     struct utimbuf    timep;
  1078.  
  1079.     /* Copy the time stamp */
  1080.     timep.actime  = statb->st_atime;
  1081.     timep.modtime = statb->st_mtime;
  1082.  
  1083.     /* Some systems (at least OS/2) do not support utime on directories */
  1084.     if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
  1085.     WARN((stderr, "%s: ", progname));
  1086.     if (!quiet) perror(ofname);
  1087.     }
  1088. }
  1089. #endif
  1090.  
  1091.  
  1092. /* ========================================================================
  1093.  * Copy modes, times, ownership from input file to output file.
  1094.  * IN assertion: to_stdout is false.
  1095.  */
  1096. local void copy_stat(ifstat)
  1097.     struct stat *ifstat;
  1098. {
  1099. #ifndef NO_UTIME
  1100.     if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
  1101.     ifstat->st_mtime = time_stamp;
  1102.     if (verbose > 1) {
  1103.         fprintf(stderr, "%s: time stamp restored\n", ofname);
  1104.     }
  1105.     }
  1106.     reset_times(ofname, ifstat);
  1107. #endif
  1108.     /* Copy the protection modes */
  1109.     if (chmod(ofname, ifstat->st_mode & 07777)) {
  1110.     WARN((stderr, "%s: ", progname));
  1111.     if (!quiet) perror(ofname);
  1112.     }
  1113. #ifndef NO_CHOWN
  1114.     chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
  1115. #endif
  1116.     remove_ofname = 0;
  1117.     /* It's now safe to remove the input file: */
  1118.     (void) chmod(ifname, 0777);
  1119.     
  1120.     // lgk don't remove input file here
  1121.  
  1122.     //if (unlink(ifname)) {
  1123.     //WARN((stderr, "%s: ", progname));
  1124.     //if (!quiet) perror(ifname);
  1125.    // }
  1126. }
  1127.  
  1128. #ifndef NO_DIR
  1129.  
  1130. /* ========================================================================
  1131.  * Recurse through the given directory. This code is taken from ncompress.
  1132.  */
  1133. local void treat_dir(dir)
  1134.     char *dir;
  1135. {
  1136.     dir_type *dp;
  1137.     DIR      *dirp;
  1138.     char     nbuf[MAX_PATH_LEN];
  1139.     int      len;
  1140.  
  1141.     dirp = opendir(dir);
  1142.     
  1143.     if (dirp == NULL) {
  1144.     fprintf(stderr, "%s: %s unreadable\n", progname, dir);
  1145.     exit_code = ERROR;
  1146.     return ;
  1147.     }
  1148.     /*
  1149.      ** WARNING: the following algorithm could occasionally cause
  1150.      ** compress to produce error warnings of the form "<filename>.gz
  1151.      ** already has .gz suffix - ignored". This occurs when the
  1152.      ** .gz output file is inserted into the directory below
  1153.      ** readdir's current pointer.
  1154.      ** These warnings are harmless but annoying, so they are suppressed
  1155.      ** with option -r (except when -v is on). An alternative
  1156.      ** to allowing this would be to store the entire directory
  1157.      ** list in memory, then compress the entries in the stored
  1158.      ** list. Given the depth-first recursive algorithm used here,
  1159.      ** this could use up a tremendous amount of memory. I don't
  1160.      ** think it's worth it. -- Dave Mack
  1161.      ** (An other alternative might be two passes to avoid depth-first.)
  1162.      */
  1163.     
  1164.     while ((dp = readdir(dirp)) != NULL) {
  1165.  
  1166.     if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
  1167.         continue;
  1168.     }
  1169.     len = strlen(dir);
  1170.     if (len + NLENGTH(dp) + 1 < MAX_PATH_LEN - 1) {
  1171.         strcpy(nbuf,dir);
  1172.         if (len != 0 /* dir = "" means current dir on Amiga */
  1173. #ifdef PATH_SEP2
  1174.         && dir[len-1] != PATH_SEP2
  1175. #endif
  1176. #ifdef PATH_SEP3
  1177.         && dir[len-1] != PATH_SEP3
  1178. #endif
  1179.         ) {
  1180.         nbuf[len++] = PATH_SEP;
  1181.         }
  1182.         strcpy(nbuf+len, dp->d_name);
  1183.         treat_file(nbuf);
  1184.     } else {
  1185.         fprintf(stderr,"%s: %s/%s: pathname too long\n",
  1186.             progname, dir, dp->d_name);
  1187.         exit_code = ERROR;
  1188.     }
  1189.     }
  1190.     closedir(dirp);
  1191. }
  1192. #endif /* ? NO_DIR */
  1193.  
  1194. /* ========================================================================
  1195.  * Free all dynamically allocated variables and exit with the given code.
  1196.  */
  1197. local int do_exit(exitcode)
  1198.     int exitcode;
  1199. {
  1200.     static int in_exit = 0;
  1201.  
  1202.     if (in_exit) return(exitcode);
  1203.     in_exit = 1;
  1204.     if (env != NULL)  free(env),  env  = NULL;
  1205.     if (args != NULL) free((char*)args), args = NULL;
  1206.     FREE(inbuf);
  1207.     FREE(outbuf);
  1208.     FREE(d_buf);
  1209.     FREE(window);
  1210. #ifndef MAXSEG_64K
  1211.     FREE(tab_prefix);
  1212. #else
  1213.     FREE(tab_prefix0);
  1214.     FREE(tab_prefix1);
  1215. #endif
  1216.     return(exitcode);
  1217. }
  1218.  
  1219. /* ========================================================================
  1220.  * Signal and error handler.
  1221.  */
  1222. RETSIGTYPE abort_gzip()
  1223. {
  1224.    if (remove_ofname) {
  1225.        close(ofd);
  1226.        unlink (ofname);
  1227.    }
  1228.    do_exit(ERROR);
  1229.    exit(ERROR);
  1230. }
  1231.